
const tf = require("@tensorflow/tfjs");
const csv = require('node-csv').createParser();
const util = require('../util.js');

let lr = 0.5	
let batchSize = 32	//每次训练多少个
let total_episode = 500	//总训练次数
let test_num = 100	//多少个数据作为 测试数据
let csvPath = './datasets/housing.csv' //csv数据文件位置

/*
*	处理csv文件
*/
const pasefile = async data => {
	const labels = []; 
	data.map(value => {
		// 将label和data分离存放
		labels.push(value[value.length - 1])
		value.splice(value.length - 1, 1)
	})
	return {'data': data, 'labels': labels}
}

//	定义参数变量
var weight_1 = tf.variable(tf.randomNormal([1, 13], 0, 0.01, 'float32', 1))
var weight_2 = tf.variable(tf.randomNormal([1, 13], 0, 0.01, 'float32', 2))
var weight_3 = tf.variable(tf.randomNormal([1, 13], 0, 0.01, 'float32', 3))
var weight_4 = tf.variable(tf.randomNormal([1, 13], 0, 0.01, 'float32', 4))
var bais_1 = tf.variable(tf.zeros([1, 1]).add(tf.scalar(0.1)))
var bais_2 = tf.variable(tf.zeros([1, 1]).add(tf.scalar(0.1)))

/*
*	定义回归预测算法
*/
const predict = x => {
	return tf.tidy(() => {
			// W_1 * X + W_2 * X^2 + b_1
			var hidden_layer = weight_1.mul(x)
							.add(weight_2.mul(x.square()))
							.add(bais_1)
			// 激活函数
			var hidden_layer_2 = tf.leakyRelu(hidden_layer)
			//	W_3 * HL_2 + W_4 * HL_2^2 + b_2 再求和
			return weight_3.mul(hidden_layer_2)
							.add(weight_4.mul(hidden_layer_2.square()))
							.add(bais_2).sum(1, true)
		})
}
/*
*	定义损失函数
*/
const loss = (pred, labels) => {
	// meanSquareError
  	return pred.sub(labels).square().mean()
}

/*
*	训练参数变量
*/
const train = async (xs, ys, numIterations = total_episode, learningRate = lr) => {
	// adam 优化函数
	const optimizer = tf.train.adam(learningRate);
	// 循环训练
	for (let iter = 0; iter < numIterations; iter++) {
		//	拿到batchSize数量的样本数据
		var sampler = util.sample(xs, ys, batchSize, false)
		//	优化
	    optimizer.minimize(() => {
	      const preds = predict(tf.tensor(sampler['test_data']));
	      const tLabel = tf.tensor(sampler['test_labels'], [batchSize, 1])
	      var losses = loss(preds, tLabel);
	      //	每10次打印loss
	      if (iter % 10 == 0) 
	      	console.log('iter : ' + iter + ' losses : ' + losses.dataSync())
	      return losses
	    });
  	}
}

csv.parseFile(csvPath, async (err, data) => {
	//	处理csv文件数据
	var pasedFile = await pasefile(data)
	// 	归一化数据
	pasedFile['data'] = await util.normlize(pasedFile['data'])
	//	训练
	train(pasedFile['data'], pasedFile['labels'])
	//	打印训练后 预测数据 和 真实数据对比
	var pred = predict(tf.tensor([pasedFile['data'][3], pasedFile['data'][1], pasedFile['data'][2]])).dataSync()
	console.log('predict label : \t' + pred[0] + "\t" + pred[1] + "\t" + pred[2])
	console.log('real label : \t\t' + pasedFile['labels'][3] + "\t\t\t" + pasedFile['labels'][1] + "\t\t\t" + pasedFile['labels'][2])
})


/*
*	以上代码最后的结果，没有分离训练数据以及测试数据，最后测试的数据预测的结果稍好，某些数据预测结果不忍直视。。。
*/